﻿using System;
using System.Data;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Data.OracleClient;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington
	Started:	2007-12-21	
	Status:		alpha	
	Version:	2.0.0
	Build:		20071221
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/

/*	-------------------------------------------------------------------------------------------------
	Note re EngineX.DataX:
	------------------------------------
	This component is intended as a data layer to abstract the use of any particular data connector.
	The original source for this was taken from the following url:
		http://aspalliance.com/837
	-------------------------------------------------------------------------------------------------	*/

/*	-----------------------------------------------------------------------
	Development Notes:
	==================
	20071221:	Starting date is a pallendrome!
	20071221:	Extend for PostGreSQL
	-----------------------------------------------------------------------	*/

namespace umlungu.engineX.dataX {
	/// <summary>
	/// 
	/// </summary>
	public sealed class DataXManager : IDataXManager, IDisposable {

		#region Constants
		private const string DataX_Connect = "DataX Error connecting: ";
		#endregion

		#region Visible properties
		private IDbConnection idbConnection;
		/// <summary></summary>
		/// <value></value>
		public IDbConnection Connection {
			get {
				idbConnection = DataXManagerFactory.GetConnection(this.providerType);
				idbConnection.ConnectionString = connectionString;
				return idbConnection; 
			}
		}

		private IDataReader idataReader;
		/// <summary></summary>
		/// <value></value>
		public IDataReader DataReader {
			get { return idataReader; }
			set { idataReader = value; }
		}

		private DataProviderType providerType;
		/// <summary></summary>
		/// <value></value>
		public DataProviderType ProviderType {
			get { return providerType; }
			set { providerType = value; }
		}

		private string connectionString;
		/// <summary></summary>
		/// <value></value>
		public string ConnectionString {
			get { return connectionString; }
			set { connectionString = value; }
		}

		private IDbCommand idbCommand;
		/// <summary></summary>
		/// <value></value>
		public IDbCommand Command {
			get {
				if (idbConnection.State != ConnectionState.Open)
					idbConnection.Open();
				idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
				return idbCommand; 
			}
		}

		private IDbTransaction idbTransaction = null;
		/// <summary></summary>
		/// <value></value>
		public IDbTransaction Transaction {
			get { return idbTransaction; }
		}

		private IDbDataParameter[] idbParameters = null;
		/// <summary></summary>
		/// <value></value>
		public IDbDataParameter[] Parameters {
			get { return idbParameters; }
		}

		private IDataParameter idbParameter;
		/// <summary>A new command parameter</summary>
		/// <value>A IDbDataParameter object</value>
		public IDataParameter Parameter {
			get { return idbParameter; }
		}
		#endregion

		#region Constructors/Destructors
		/// <summary>
		/// Default constructor
		/// </summary>
		public DataXManager() {
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="providerType"></param>
		public DataXManager(DataProviderType providerType) {
			this.providerType = providerType;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="providerType"></param>
		/// <param name="connectionString"></param>
		public DataXManager(DataProviderType providerType, string connectionString) {
			this.providerType = providerType;
			this.connectionString = connectionString;
		}
		#endregion

		#region Public methods

		/// <summary>
		/// Opens a connection to the data provider
		/// </summary>
		/// <returns>A connection (IDbConnection object) to the data provider</returns>
		public IDbConnection Connect() {
			try {
				idbConnection = DataXManagerFactory.GetConnection(this.providerType, connectionString);
				return idbConnection;
			} catch (Exception e) {
				throw new DataXException("DataX_Connect", String.Concat(DataX_Connect, e.Message, " [", connectionString, "]"));
			}
		}

		/// <summary>
		/// Gets a command object and sets the connection
		/// </summary>
		/// <returns>A command (IDbCommand) object</returns>
		public IDbCommand GetCommand() {
			if (idbConnection.State != ConnectionState.Open)
				idbConnection.Open();
			idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			idbCommand.Connection = idbConnection;
			return idbCommand;
		}

		/// <summary>
		/// Gets a command object and sets the connection and stored procedure
		/// </summary>
		/// <returns>A command (IDbCommand) object</returns>
		public IDbCommand GetCommand(string command) {
			return GetCommand(command, true);
		}

		/// <summary>
		/// Gets a command object and sets the connection and command text
		/// </summary>
		/// <returns>A command (IDbCommand) object</returns>
		public IDbCommand GetCommand(string command, bool isStoredProc) {
			if (idbConnection.State != ConnectionState.Open)
				idbConnection.Open();
			idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			idbCommand.Connection = idbConnection;
			idbCommand.CommandText = command;
			idbCommand.CommandType = (isStoredProc) ? CommandType.StoredProcedure : CommandType.Text;
			return idbCommand;
		}

		/// <summary>
		/// Opens a connection to the database and creates a command object (IDbCommand)
		/// </summary>
		public void Open() { 
			idbConnection = DataXManagerFactory.GetConnection(this.providerType);
			idbConnection.ConnectionString = this.ConnectionString;
			if (idbConnection.State != ConnectionState.Open)
				idbConnection.Open();
			this.idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
		}

		/// <summary>
		/// 
		/// </summary>
		public void Close() {
			if (idbConnection.State !=ConnectionState.Closed)
				idbConnection.Close();
		}

		/// <summary>
		/// 
		/// </summary>
		public void Dispose() {
			GC.SuppressFinalize(this);
			this.Close();
			this.idbCommand = null;
			this.idbTransaction = null;
			this.idbConnection = null;
		}

		/// <summary>
		/// 
		/// </summary>
		public IDataParameter CreateParameter(string paramName, DbType paramType) {
			idbParameter = DataXManagerFactory.GetParameter(this.ProviderType, paramName, paramType);
			return idbParameter;
		}

		/// <summary>
		/// 
		/// </summary>
		public IDataParameter CreateParameter(string paramName, DbType paramType, int paramLength) {
			idbParameter = DataXManagerFactory.GetParameter(this.ProviderType, paramName, paramType, paramLength);
			return idbParameter;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="paramsCount"></param>
		public void CreateParameters(int paramsCount) {
			idbParameters = new IDbDataParameter[paramsCount];
			idbParameters = DataXManagerFactory.GetParameters(this.ProviderType, paramsCount);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="index"></param>
		/// <param name="paramName"></param>
		/// <param name="objValue"></param>
		public void AddParameters(int index, string paramName, object objValue) {
			if (index < idbParameters.Length) {
				idbParameters[index].ParameterName = paramName;
				idbParameters[index].Value = objValue;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void BeginTransaction() {
			if (this.idbTransaction == null)
				idbTransaction = DataXManagerFactory.GetTransaction(this.ProviderType);
			this.idbCommand.Transaction = idbTransaction;
		}

		/// <summary>
		/// 
		/// </summary>
		public void CommitTransaction() {
			if (this.idbTransaction != null)
				this.idbTransaction.Commit();
			idbTransaction = null;
		}

		/// <summary>
		/// 
		/// </summary>
		public void RollBackTransaction() {
			if (this.idbTransaction != null)
				this.idbTransaction.Rollback();
			idbTransaction = null;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandType"></param>
		/// <param name="commandText"></param>
		/// <returns></returns>
		public IDataReader ExecuteReader(CommandType commandType, string commandText) {
			this.idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			idbCommand.Connection = idbConnection;
			PrepareCommand(idbCommand, idbConnection, this.Transaction, commandType, commandText, this.Parameters);
			this.DataReader = idbCommand.ExecuteReader();
			idbCommand.Parameters.Clear();
			return this.DataReader;
		}

		/// <summary>
		/// 
		/// </summary>
		public void CloseReader() {
			if (this.DataReader != null)
				this.DataReader.Close();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandType"></param>
		/// <param name="commandText"></param>
		/// <returns></returns>
		public int ExecuteNonQuery(CommandType commandType, string commandText) {
			this.idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			PrepareCommand(idbCommand, idbConnection, this.Transaction, commandType, commandText, this.Parameters);
			int returnValue = idbCommand.ExecuteNonQuery();
			idbCommand.Parameters.Clear();
			return returnValue;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandType"></param>
		/// <param name="commandText"></param>
		/// <returns></returns>
		public object ExecuteScalar(CommandType commandType, string commandText) {
			this.idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			PrepareCommand(idbCommand, idbConnection, this.Transaction, commandType, commandText, this.Parameters);
			object returnValue = idbCommand.ExecuteScalar();
			idbCommand.Parameters.Clear();
			return returnValue;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandType"></param>
		/// <param name="commandText"></param>
		/// <returns></returns>
		public DataSet ExecuteDataSet(CommandType commandType, string commandText) {
			this.idbCommand = DataXManagerFactory.GetCommand(this.ProviderType);
			PrepareCommand(idbCommand, idbConnection, this.Transaction, commandType, commandText, this.Parameters);
			IDbDataAdapter dataAdapter = DataXManagerFactory.GetDataAdapter(this.ProviderType);
			dataAdapter.SelectCommand = idbCommand;
			DataSet dataSet = new DataSet();
			dataAdapter.Fill(dataSet);
			idbCommand.Parameters.Clear();
			return dataSet;
		}
		#endregion

		#region Protected methods
		#endregion

		#region Private methods
		/// <summary>
		/// 
		/// </summary>
		/// <param name="command"></param>
		/// <param name="commandParameters"></param>
		private void AttachParameters(IDbCommand command, IDbDataParameter[] commandParameters) {
			foreach (IDbDataParameter idbParameter in commandParameters) {
				if ((idbParameter.Direction == ParameterDirection.InputOutput) && (idbParameter.Value == null)) {
					idbParameter.Value = DBNull.Value;
				}
				command.Parameters.Add(idbParameter);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="command"></param>
		/// <param name="connection"></param>
		/// <param name="transaction"></param>
		/// <param name="commandType"></param>
		/// <param name="commandText"></param>
		/// <param name="commandParameters"></param>
		private void PrepareCommand(IDbCommand command, IDbConnection connection, IDbTransaction transaction, CommandType commandType, string commandText, IDbDataParameter[] commandParameters) {
			command.Connection = connection;
			command.CommandText = commandText;
			command.CommandType = commandType;

			if (transaction != null) {
				command.Transaction = transaction;
			}

			if (commandParameters != null) {
				AttachParameters(command, commandParameters);
			}
		}

		#endregion
	}
}